﻿// ScannerTest.cs
//
// Copyright 2008 by Burt Harris
// Licensed under the Microsoft Public License (Ms-PL)
// See: http://www.codeplex.com/yaml/license
//

using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace YaTools.Yaml.UnitTests
{
    [TestClass]
    public class ScannerTest : Scanner
    {
        private const string TestString1 = "One two three four, fifty-five";
        private const string TwoLineStringCR = "One two three\rxfour five";
        private const string TwoLineStringLF = "One two three\nxfour five";
        private const string TwoLineStringCRLF = "One two three\r\nxfour five";
        public TestContext TestContext { get; set; }

        [TestInitialize]
        public void MyTestInitialize()
        {
            // Catch Debug.Assert & Trace.Asserts

            SetSource(TestString1);
            BeginScan();
        }

        [TestMethod]
        [ExpectedException(typeof (ArgumentOutOfRangeException))]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void BackupException1()
        {
            Backup(1); // Can't backup at beginning of buffer
        }

        [TestMethod]
        [ExpectedException(typeof (ArgumentOutOfRangeException))]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void BackupException2()
        {
            Read();
            Backup(10); // Can't backup at beginning of buffer
        }


        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void ReadCharTest()
        {
            for (int i = 0; i < TestString1.Length; i++)
            {
                Assert.AreEqual(TestString1[i], Read());
            }
            Assert.AreEqual(Unicode.EOS, Read());
        }

        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void SkipWhiteSpaceTest()
        {
            SetSource("     \tFiveleadingSpacess and one tab before");
            ReadSpacesAndTabs();
            Assert.AreEqual(6, Offset);
        }

        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void WordTest()
        {
            Assert.IsTrue(Read("One "));
            Assert.IsFalse(Read("flubber"));
            Assert.AreEqual(4, Offset);
        }


        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void SkipSpacesTest()
        {
            SetSource("     \tFiveleadingSpacess and one tab before");
            SkipSpaces();
            Assert.AreEqual(5, Offset);
        }

        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void SaveOffsetTest()
        {
            Assert.AreEqual(0, Offset);
            using (SaveOffset())
            {
                for (int i = 0; i < 5; i++)
                    Read();
                Assert.AreEqual(5, Offset);
                Assert.AreEqual('w', Read());
            }
            Assert.AreEqual(0, Offset);
            Assert.AreEqual('O', Read());
        }

        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void PeekTest()
        {
            Assert.AreEqual('O', Peek());
            Assert.AreEqual('O', Read());
            Assert.AreEqual('n', Peek());
            Assert.AreEqual('n', Read());
            Assert.AreEqual('e', Peek());
            Assert.AreEqual('e', Read());
            Assert.AreEqual(' ', Peek());
            Assert.AreEqual(' ', Read());
        }

        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void MatchAndConsumeTest()
        {
            Assert.IsTrue(Read("One"));
            Assert.IsTrue(Read(" "));
            Assert.IsFalse(Read("Never"));
            Assert.IsTrue(Read("two"));
            EndToken();
            Assert.AreEqual("One two", TokenText);
        }

        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void FinishWordTest()
        {
            FinishWord();
            Assert.AreEqual(3, Offset);
        }

        //[TestMethod()]
        //[DeploymentItem( "YaTools.Yaml.Core.Net4.dll" )]
        //public void ReadStringTest()
        //{
        //    var reader = new StringReader( "One Two" );
        //    var location = SourceLocation.MinValue;
        //    var buffer = new TokenizerBuffer( reader, location, 512, true );

        //    Assert.IsTrue( buffer.Read( "One" ) );
        //    Assert.IsTrue( buffer.Read( " Two" ) );
        //}

        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "EOL")]
        public void AdvanceToEOLTest()
        {
            ReadLine();
            Assert.AreEqual(Unicode.EOS, Read());

            SetSource(TwoLineStringCR);
            ReadLine();
            SkipEOL();
            Assert.AreEqual('x', Read());

            SetSource(TwoLineStringCR);
            ReadLine();
            SkipEOL();
            Assert.AreEqual('x', Read());


            SetSource(TwoLineStringCRLF);
            ReadLine();
            SkipEOL();
            Assert.AreEqual('x', Read());

            SetSource(TwoLineStringLF);
            ReadLine();
            SkipEOL();
            Assert.AreEqual('x', Read());
        }

        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void AdvanceToTest()
        {
            AdvanceTo("Tt".ToCharArray());
            Assert.AreEqual(4, Offset);
        }

        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void AdvanceOverTest()
        {
            AdvanceOver(" enoENO".ToCharArray(), 8);
            Assert.AreEqual(4, Offset);
        }

        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void PeekTest2()
        {
            ReadLine();
            Assert.AreEqual(Unicode.EOS, Peek());
        }

        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        //[ExpectedException(typeof(System.IO.EndOfStreamException))]
        public void ReadCharTest2()
        {
            ReadLine();
            Assert.AreEqual(Unicode.EOS, Read());
        }

        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        public void ParseTextTest()
        {
            FinishWord();
            Assert.AreEqual("One", TokenText);
            Assert.AreEqual(3, Offset);
            SkipSpaces();
            EndToken();
            BeginScan();
            Assert.AreEqual(4, Offset);
            Read();
            Assert.AreEqual(5, Offset);
            FinishWord();
            Assert.AreEqual("two", TokenText);

            SkipSpaces();
            EndToken();
            BeginScan();
            Read();
            FinishWord();
            Assert.AreEqual("three", TokenText);
        }

        [TestMethod]
        [DeploymentItem("YaTools.Yaml.Core.Net4.dll")]
        [DeploymentItem(@"CoreUnitTest\Yaml_1.2\02.02.b.yaml")]
        public void FromFileTest()
        {
            using (var reader = File.OpenText("02.02.b.yaml"))
            {
                SetSource(reader);
                BeginScan();
                ReadLine();
                EndToken();
                Assert.AreEqual("%YAML 1.2", TokenText);
            }
        }

        [TestMethod]
        public void Streaming()
        {
            const int reps = 10000;

            var sb = new StringBuilder();
            for (int i = 0; i < reps; i++)
                sb.Append("0123456789");

            SetSource(sb.ToString());

            for (int i = 0; i < reps; i++)
            {
                Assert.AreEqual('0', Peek(0));
                Assert.AreEqual('1', Peek(1));
                Assert.AreEqual('2', Peek(2));
                Assert.AreEqual('3', Peek(3));
                Assert.AreEqual('4', Peek(4));
                Assert.AreEqual('5', Peek(5));
                Assert.AreEqual('6', Peek(6));
                Assert.AreEqual('7', Peek(7));
                Assert.AreEqual('8', Peek(8));
                Assert.AreEqual('9', Peek(9));

                Assert.AreEqual('0', Peek());
                Read();
                Assert.AreEqual('1', Peek());
                Read();
                Assert.AreEqual('2', Peek());
                Read();
                Assert.AreEqual('3', Peek());
                Read();
                Assert.AreEqual('4', Peek());
                Read();
                Assert.AreEqual('5', Peek());
                Read();
                Assert.AreEqual('6', Peek());
                Read();
                Assert.AreEqual('7', Peek());
                Read();
                Assert.AreEqual('8', Peek());
                Read();
                Assert.AreEqual('9', Peek());
                Read();
            }
            Assert.AreEqual('\xffff', Peek());
            Read();
            Assert.AreEqual('\xffff', Peek());
            Read();
            Assert.AreEqual('\xffff', Peek());
            Read();
            Assert.AreEqual('\xffff', Peek());
            Read();
            Assert.AreEqual('\xffff', Peek());
            Read();
        }

        [TestMethod]
        public void ReaderTestLF()
        {
            ReaderSub("1\n");
            ReaderSub("12\n");
            ReaderSub("123\n");
            ReaderSub("1234\n");
            ReaderSub("12345\n");
            ReaderSub("123456\n");
            ReaderSub("1234567\n");
            ReaderSub("12345678\n");
            ReaderSub("123456789\n");
        }


        [TestMethod]
        public void ReaderTestCRLF()
        {
            ReaderSub("1\r\n");
            ReaderSub("12\r\n");
            ReaderSub("123\r\n");
            ReaderSub("1234\r\n");
            ReaderSub("12345\r\n");
            ReaderSub("123456\r\n");
            ReaderSub("1234567\r\n");
            ReaderSub("12345678\r\n");
            ReaderSub("123456789\r\n");
        }

        public void ReaderSub(string data)
        {
            var sb = new StringBuilder();
            for (int i = 0; i < 10000; i++)
            {
                sb.Append(data);
            }
            SetSource(sb.ToString());
            BeginScan();

            char c;
            int index = 0;
            int line = 1;

            while ((c = Peek()) != '\xffff')
            {
                if (IsBreak(c))
                {
                    line++;
                    SkipEOL();
                    if (c == '\r')
                        index++;
                }
                else
                {
                    int column = (c - '0');
                    Assert.AreEqual(column, CurrentLocation.Column);
                    Assert.AreEqual(line, CurrentLocation.Line);
                    Assert.AreEqual(index, CurrentLocation.Index);
                    Read();
                }
                index++;
            }
        }
    }
}